package org.grill.clovercash;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;

import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.grill.clovercash.accounts.Account;
import org.grill.clovercash.accounts.Split;
import org.grill.clovercash.accounts.Transaction;
import org.grill.clovercash.accounts.Account.DeltaEvent;
import org.grill.clovercash.accounts.Account.IDeltaListener;
import org.grill.clovercash.ui.SplitRowView;
import org.joda.time.LocalDate;

public class AccountLedgerView extends ViewPart implements SplitRowOwner {
	@Override
	public void init(IViewSite site, IMemento memento) throws PartInitException {
		super.init(site);

		if (memento != null) {
			String accountName = memento.getString("accountname");
			Account findAccount = CloverCashUIPlugin.getDefault().getRootAccount().findAccount(accountName);
			if (findAccount != null)
				account = findAccount;
		}
	}

	@Override
	public void saveState(IMemento memento) {
		memento.putString("accountname", account.getDisplayName());
	}

	public static final String ID = "org.grill.clovercash.accountledgerview";
	
	private boolean initialized;
	
	private Composite parent;

	private Account account;
	
	public AccountLedgerView() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public void createPartControl(Composite tmp) {
		scroll = new ScrolledComposite(tmp, SWT.V_SCROLL | SWT.V_SCROLL);
		scroll.setExpandVertical(true);
		scroll.setExpandHorizontal(true);
		
		this.parent = new Composite(scroll, SWT.NONE);
		scroll.setContent(this.parent);
//		parent.setSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		GridLayout gridLayout = new GridLayout();
		gridLayout.verticalSpacing = 0;
		parent.setLayout(gridLayout);
		
		addActionBars();

		if (account != null)
			setAccount(account);
	}
	
	private void addActionBars() {
		IActionBars bars = getViewSite().getActionBars();
		IToolBarManager toolBarManager = bars.getToolBarManager();
		toolBarManager.add(new ToggleReconciledAction());
	}
	
	class ToggleReconciledAction extends org.eclipse.jface.action.Action {
		ToggleReconciledAction() {
			super("Toggle Reconciled", PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_OBJ_ELEMENT));
		}
		
		@Override
		public void run() {
			showingReconciled = !showingReconciled;
			redraw();
		}
	}

	@Override
	public void setFocus() {
	}
	
	public boolean isInitialized() {
		return initialized;
	}

	public void setAccount(Account a) {
		account = a;
		if (!initialized) {
			account.addListener(new IDeltaListener() {
				public void remove(DeltaEvent event) {
					add(event);
				}
			
				public void add(DeltaEvent event) {
					if (event.data == AccountLedgerView.this)
						return;
					
					redraw();
				}
			});
			
			buildView();
		}
		
		initialized = true;
	}
	
	private ArrayList<SplitRowView> rows = new ArrayList<SplitRowView>();

	boolean showingReconciled = false;
	
	private Label reconciledTotalLabel = null;
	
	private void buildView() {
		setPartName(account.getDisplayName());
		BigDecimal total = new BigDecimal(0);
		Collections.sort(account.getSplits(), new SplitComparator());

		
		boolean showReconciledLabel = false;
		
		for (Split s : account.getSplits()) {
			total = total.add(s.value);

			
			if (!showingReconciled) 
				if (s.reconciled) {
					showReconciledLabel = true;
					continue;
				}
			
			if (showReconciledLabel) 
			{
				reconciledTotalLabel = new Label(parent, SWT.LEFT);
				reconciledTotalLabel.setText("Reconciled Total: " + NumberFormat.getCurrencyInstance().format(total));
				showReconciledLabel = false;
			}
			
			SplitRowView splitRowView = new SplitRowView(parent, this, account, s);
			splitRowView.setTotal(total);
			rows.add(splitRowView);

		}
		rows.add(new SplitRowView(parent, this, account, lastNewEntryDate));
		scroll.setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		scroll.getParent().layout(true, true);
	}

	private SplitRowView currentActiveRow = null;

	private ScrolledComposite scroll;
	
	/* (non-Javadoc)
	 * @see org.grill.clovercash.SplitRowOwner#shouldActivate(org.grill.clovercash.ui.SplitRowView)
	 */
	public boolean shouldActivate(SplitRowView view) {
		if (currentActiveRow == null) {
			currentActiveRow = view;
			return true;
		}
		
		if (!currentActiveRow.isModified()) {
			currentActiveRow.disableWidgets();
			currentActiveRow = view;
			return true;
		}
		
		MessageDialog dlg = new MessageDialog(getSite().getShell(), "Accept Changes?", null, "Do you wish to save these changes?", MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
		int val = dlg.open();
		
		if (val == IDialogConstants.CANCEL_ID)
			return false;
		
		if (val == IDialogConstants.NO_ID)
		{
			currentActiveRow.fillData();
		} else {
			if (currentActiveRow.validate()) {
				if (currentActiveRow.isNew()) {
					saveNewData(currentActiveRow);
				} else {
					saveChangedData(currentActiveRow);
				}
				updateTotals();
			} else return false;
		}
		
		currentActiveRow.disableWidgets();
		
		currentActiveRow = view;
		return true;
	}
	
	/* (non-Javadoc)
	 * @see org.grill.clovercash.SplitRowOwner#saveRow()
	 */
	public boolean saveRow() {
		if (currentActiveRow.validate()) {
			if (currentActiveRow.isNew()) {
				saveNewData(currentActiveRow);
			} else {
				saveChangedData(currentActiveRow);
				currentActiveRow.disableWidgets();
				currentActiveRow = null;
			}
			updateTotals();
			return true;
		} else return false;
	}
	
	/* (non-Javadoc)
	 * @see org.grill.clovercash.SplitRowOwner#cancelRowChange()
	 */
	public void cancelRowChange() {
		currentActiveRow.fillData();
		currentActiveRow.disableWidgets();
		currentActiveRow = null;
	}

	private void saveChangedData(SplitRowView row) {
		Split split = row.getSplit();
		Transaction tx = split.trans;
		tx.description = row.getDescription();
		tx.date = row.getDate();
		
		split.value = row.getValue();
		Split otherSplit = tx.getOther(split);
		otherSplit.value = split.value.negate();
		
		Account currentOther = otherSplit.owner;
		Account newOther = row.getOtherAccount();
		
		if (newOther != currentOther) {
			currentOther.getSplits().remove(otherSplit);
			newOther.getSplits().add(otherSplit);
			
			otherSplit.owner = newOther;
			
			// need to notify both
			currentOther.changed(tx);
		}
		newOther.changed(tx);
	}

	private void updateTotals() {
		BigDecimal total = new BigDecimal(0);
		if (!showingReconciled)
			for (Split s : account.getSplits())
			{
				if (!s.reconciled)
					break;
				total = total.add(s.value);
			}
				
		for (Control c : parent.getChildren()) {
			if (c instanceof SplitRowView) {
				SplitRowView row = (SplitRowView) c;
				Split split = row.getSplit();
				if (split != null) {
					total = total.add(split.value);
					row.setTotal(total);
				}
			}
		}
	}

	private LocalDate lastNewEntryDate = new LocalDate(); 
	
	private void saveNewData(SplitRowView row) {
		Account other = row.getOtherAccount();
		String desc = row.getDescription();
		LocalDate date = row.getDate();
		BigDecimal value = row.getValue();
		lastNewEntryDate = date;
		
		// add splits
		Transaction tx = new Transaction(account, other, desc, value, date);
		row.setSplit(tx.splits[0]);
		
		// set current row to not new
		row.setNew(false);
		
		row.enableWidgets(false);

		System.out.println("Creating new row...");
		SplitRowView splitRowView = new SplitRowView(parent, this, account, lastNewEntryDate);
		rows.add(splitRowView);
//		splitRowView.fillData();
		splitRowView.enableWidgets(true);
		splitRowView.setDescActive();
		currentActiveRow = splitRowView;
		scroll.setMinSize(parent.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		scroll.setOrigin(-1, Integer.MAX_VALUE);
		scroll.layout(true, true);
		
		account.changed(tx);
		other.changed(tx);
	}

	private void redraw() {
		if (parent.isDisposed())
			return;
		
		Control[] children = parent.getChildren();
		for (Control child : children)
			child.dispose();
		buildView();
	}
	

	public boolean showBothAccounts() {
		return false;
	}
}
